package types

import (
	"fmt"
	"gitee.com/kristas/booting-go/framework/common/util/convert"
	"log"
	"strconv"
	"strings"
)

// Controller
// is handle http request and response
//
// param:
//
// - `group` define prefix handler
type Controller struct {
	Component
}

func (c *Controller) Group() string {
	return c.getOrDefault("group")
}

// FsController
// is handle static assets
//
// param:
//
// - `compile` define whether to use html/template compile
type FsController struct {
	Controller
}

func (f *FsController) Compile() bool {
	inference, err := convert.Inference(f.getOrDefault("compile"))
	if err != nil {
		log.Fatal(err)
	}
	compile, ok := inference.(bool)
	if !ok {
		log.Fatal(fmt.Sprintf("Factory Bean inference `singleton` type as bool faied: %s", err))
	}
	return compile
}

// Service
// is service layer
//
// param:
//
// - `service` define service name
type Service struct {
	Component
}

func (c *Service) ServiceFor() string {
	return c.getOrDefault("service")
}

// Repository
// is persistence layer
//
// param:
//
// - `table` define table
type Repository struct {
	Component
}

func (c *Repository) Table() string {
	return c.getOrDefault("table")
}

// AutoConfigure
// can auto compile and inject config
//
// param:
//
// - `prefix` define prefix in config file
type AutoConfigure struct {
	Component
}

func (c *AutoConfigure) Prefix() string {
	return c.getOrDefault("prefix")
}

// ApplicationRunner
// can be called automate when framework boot up
//
// param:
//
// - `order` define call sequence
type ApplicationRunner struct {
	Component
}

func (a *ApplicationRunner) Order() int {
	order, err := strconv.Atoi(a.getOrDefault("order"))
	if err != nil {
		log.Fatal(err)
	}
	return order
}

// Filter
// is http servlet filter, can optimize request and response
//
// param:
//
// - `order` define filter sequence
//
// - `pattern` define url matching pattern
type Filter struct {
	Component
}

func (f *Filter) Order() int {
	order, err := strconv.Atoi(f.getOrDefault("order"))
	if err != nil {
		log.Fatal(err)
	}
	return order
}

func (f *Filter) UrlPatterns() []string {
	pattern := f.getOrDefault("pattern")
	patterns := strings.Split(pattern, ",")
	return patterns
}

type FeignClient struct {
	Component
}

func (f *FeignClient) Name() string {
	return f.getOrDefault("name")
}

func (f *FeignClient) Url() string {
	return f.getOrDefault("url")
}

func (f *FeignClient) Path() string {
	return f.getOrDefault("path")
}

// FactoryBean
// can produce bean dynamic
//
// param:
//
// - `singleton` define factory bean produce singleton bean or not
type FactoryBean struct {
	Component
}

func (f *FactoryBean) IsSingleton() bool {
	inference, err := convert.Inference(f.getOrDefault("singleton"))
	if err != nil {
		log.Fatal(err)
	}
	singleton, ok := inference.(bool)
	if !ok {
		log.Fatal(fmt.Sprintf("Factory Bean inference `singleton` type as bool faied: %s", err))
	}
	return singleton
}

// Websocket
// can upgrade http request to websocket
//
// param:
//
// - `endpoint` define websocket endpoint
type Websocket struct {
	Component
}

func (w *Websocket) Endpoint() string {
	return w.getOrDefault("endpoint")
}

// DataSourceDriver
// used to adapter multiple type db
//
// param:
//
// - `type` define datasource type
//
// - `driver` define datasource type
type DataSourceDriver struct {
	Component
}

func (d *DataSourceDriver) Type() string {
	return d.getOrDefault("type", "database/sql")
}

func (d *DataSourceDriver) Driver() string {
	return d.getOrDefault("driver", "github.com/go-sql-driver/mysql")
}
